knitr::opts_chunk$set(echo = TRUE)
So far I have not yet implemented the workflow to securely host RTutor problem sets on your own web server and use it for teaching.
This vignette only describes ideas how web hosting can be done.
In the moment, I use RTutor for more advanced classes and let students solve the RTutor problem sets on their own computer and then submit the solution via Moodle. Alternatively, one could host the problem sets on a web server so that students can solve them with their web browser without any need to install R.
I see the main advantage of web hosting in reducing the work that arises if students have problems setting up their R environment with all required packages. This seems mainly an issue in large introductionary classes. There, you want to give students a smooth and easy experience for their first steps with R and not demotivate them with all the hazzle of installing all necessary software and packages. Also, you don't want your TAs to spend most of their time setting up the computers of those students who don't manage the installation on their own.
On the other hand, for smaller, more advanced classes, I clearly prefer that students manage these issues and solve their problems sets on their own computer using the RStudio interface of RTutor instead of the shiny, but more artificial web interface.
Just hosting RTutor problem sets in the web is no problem with shiny server. The main challenge is to host them securely in the web. If students can run arbitrary R code with priviliged access, they may read sensitive files from your server, implant a virus, delete or corrupt important data or highjack your server for other nasty things.
Note: These security mechanisms are neccessary if you want to host RTutor problem sets on your own server. They are not neccesary if you just distribute the problem sets to your students who solve them on their own computer.
As an outer shell for security, it is strictly recommended to use RAppArmor to limit file access to the minimum that is required to run your problem set and save a user's progress. You should call RAppArmor in your global.R
file for your file and set a profile that prevents file access beyond what is neccessary to run the problem set.
# Example code in global.R to set a restricted profile in RAppArmor library(RAppArmor) aa_getcon() if (!aa_is_enabled()) stop("AppArmor is not enabled.") # Set profile with limited file access aa_change_profile("outer-armor-myapp")
Even if you believe that some other security mechanisms of RTutor, like the noeval mode, may perhaps be sufficient to prevent malicious attacks, you should always use RAppArmor as an extra layer to prevent undesired access to your server. I cannot rule out that there are bugs in RTutor that create loopholes for malicious access.
To repeat: Never put an RTutor shiny app on your server without an outer layer of approbriate RAppArmor protection!
Users first start with LoginApp that then opens a link to the PSApp. Both apps can have two separate RAppArmor profiles. Only in the ps app can the user enter more or less arbitrary code.
To store students' progress and evaluate their performance, we need a password secured login mechanism. While shiny server pro allows you to use well established authentification mechanisms, I also try to include a simple login mechanism for the open version of shiny-server. The details are explained farther below.
The login app needs access to a database in which user names, password hashes and salts are stored. Yet, we want RAppArmor to forbid the ps app any read or write access to this user database. Even if a password is stored as a salted hash, you can crack it, if you run a computer long enough. So nobody should be able to infiltrate in a chunk some clever R code that downloads the stored hashes.
If the two apps are independent shiny apps, we can give different file access with RAppArmor for the apps and exclude PSApp from accessing the data base with user passwords hashes.
The key idea is as follows:
The user logs in with the LoginApp
LoginApp then creates a temporary session key (e.g. HBBWdg32b476THBEDGb4z6dh73dg476r) and stores it in a file HBBWdg32b476THBEDGb4z6dh73dg476r.ses
with a name equal to the key.
The session file is stored in a folder to which LoginApp has write access and PSApp has read access. An app's access rights are controlled via RAppArmor. While PSApp can read files from the directory, it has not access to list the existing files in the directory, i.e. it does not know which session files exist.
The temporary session file contains several pieces of information: - The username - the time of creation - possibly some information from session$clientData that may help to identify the client's computer. (To prevent simple login by copying the session key from another computer. It cannot fool more sophisticated attacks)
https://www.mypsapp.com?key=HBBWdg32b476THBEDGb4z6dh73dg476r
.
It then checks whether a session file with the corresponding name HBBWdg32b476THBEDGb4z6dh73dg476r.ses
exists, and if it is not older than a specified maximum login time (e.g. 3 hours). If these conditions are not met, access is denied. If access is given PSApp reads the user name, loads the corresponding .ups file and shows the problem set given the state stored in the user's .ups file.If the problem set is shown in noeval mode, no user code is evaluated. This requires that the problem set was created with the option preknit = TRUE
so that the knitted sample solution already exists.
The code is only parsed and the unevaluated calls are compared to the sample solution. Also automatic hints do not evaluate the code, but try to give a hint based on the unevaluated studen't expression. If the user's input passes the tests, the preknitted sample solution is shown as output.
Make sure that you have set all required read and write permissions for the files that the user "shiny" needs to access. I am speaking here of the normal Linux file permissions, not the permissions in the RAppArmor profile. Typically you will run RStudio on the server with a different user, who may have more permissions that the shiny server user.
It seems that you also need to set write permissions to directories. For example, my login app showed a grey screen once when there was no write permission to the /db
directory.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.